/**
 * @file test_platform_device.cpp
 * @author 心流 (iFlow CLI)
 * @brief 测试OpenCL平台和设备查询相关功能
 * @version 0.1
 * @date 2025-11-26
 *
 * @copyright Copyright (c) 2025
 *
 */
#define BOOST_TEST_MODULE TestPlatformDevice
#include <CL/cl.h>

#include <boost/format.hpp>
#include <boost/test/included/unit_test.hpp>
#include <boost/timer/timer.hpp>
#include <vector>

#include "test_fixture.hpp"
#include "utility.hpp"

// 测试获取平台ID
BOOST_AUTO_TEST_CASE(TestGetPlatformIDs)
{
    auto platforms = GetPlatforms();
    BOOST_CHECK_GT(platforms.size(), 0);  // 至少应该有一个平台

    // 验证获取的平台ID是否有效
    for (cl_uint i = 0; i < platforms.size(); i++)
    {
        BOOST_CHECK(platforms[i] != nullptr);

        // 检查平台信息
        char   platform_name[256];
        cl_int err = clGetPlatformInfo(platforms[i],
                                       CL_PLATFORM_NAME,
                                       sizeof(platform_name),
                                       platform_name,
                                       nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
        BOOST_CHECK_GT(strlen(platform_name), 0);

        char platform_version[256];
        err = clGetPlatformInfo(platforms[i],
                                CL_PLATFORM_VERSION,
                                sizeof(platform_version),
                                platform_version,
                                nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
        BOOST_CHECK_GT(strlen(platform_version), 0);

        char platform_vendor[256];
        err = clGetPlatformInfo(platforms[i],
                                CL_PLATFORM_VENDOR,
                                sizeof(platform_vendor),
                                platform_vendor,
                                nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
        BOOST_CHECK_GT(strlen(platform_vendor), 0);
    }
}

// 测试获取设备ID
BOOST_AUTO_TEST_CASE(TestGetDeviceIDs)
{
    auto platforms = GetPlatforms();
    BOOST_REQUIRE_GT(platforms.size(), 0);

    // 使用第一个平台获取设备
    cl_platform_id platform = platforms[0];
    auto           devices  = GetDevices(platform);
    BOOST_CHECK_GT(devices.size(), 0);  // 至少应该有一个设备

    // 验证获取的设备ID是否有效
    for (cl_uint i = 0; i < devices.size(); i++)
    {
        BOOST_CHECK(devices[i] != nullptr);

        // 检查设备信息
        char   device_name[256];
        cl_int err = clGetDeviceInfo(devices[i],
                                     CL_DEVICE_NAME,
                                     sizeof(device_name),
                                     device_name,
                                     nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
        BOOST_CHECK_GT(strlen(device_name), 0);

        cl_device_type device_type;
        err = clGetDeviceInfo(devices[i],
                              CL_DEVICE_TYPE,
                              sizeof(device_type),
                              &device_type,
                              nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
        // 设备类型应为有效的OpenCL设备类型
        BOOST_CHECK((device_type & (CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU |
                                    CL_DEVICE_TYPE_ACCELERATOR |
                                    CL_DEVICE_TYPE_CUSTOM)) != 0);

        cl_uint max_compute_units = 0;
        err                       = clGetDeviceInfo(devices[i],
                              CL_DEVICE_MAX_COMPUTE_UNITS,
                              sizeof(max_compute_units),
                              &max_compute_units,
                              nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
        BOOST_CHECK_GT(max_compute_units, 0);
    }
}

// 测试CLWrapper中获取平台和设备的方法
BOOST_AUTO_TEST_CASE(TestCLWrapperGetPlatformAndDevice)
{
    CLTestFixture fixture;

    // 测试获取平台ID
    cl_platform_id platform_id = fixture.platform_;
    BOOST_CHECK(platform_id != nullptr);

    // 测试获取设备ID
    cl_device_id device_id = fixture.device_;
    BOOST_CHECK(device_id != nullptr);

    // 验证平台和设备信息
    char   platform_name[256];
    cl_int err = clGetPlatformInfo(platform_id,
                                   CL_PLATFORM_NAME,
                                   sizeof(platform_name),
                                   platform_name,
                                   nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(strlen(platform_name), 0);

    char device_name[256];
    err = clGetDeviceInfo(
        device_id, CL_DEVICE_NAME, sizeof(device_name), device_name, nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_CHECK_GT(strlen(device_name), 0);
}

// 测试不同的设备类型
BOOST_AUTO_TEST_CASE(TestDeviceTypeFiltering)
{
    auto platforms = GetPlatforms();
    BOOST_REQUIRE_GT(platforms.size(), 0);

    cl_platform_id platform = platforms[0];

    // 测试获取CPU设备
    cl_uint num_cpu_devices = 0;
    cl_int  err             = clGetDeviceIDs(
        platform, CL_DEVICE_TYPE_CPU, 0, nullptr, &num_cpu_devices);
    // 不要求必须有CPU设备，因为可能不存在

    if (num_cpu_devices > 0)
    {
        std::vector<cl_device_id> cpu_devices(num_cpu_devices);
        err = clGetDeviceIDs(platform,
                             CL_DEVICE_TYPE_CPU,
                             num_cpu_devices,
                             cpu_devices.data(),
                             nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);

        for (cl_uint i = 0; i < num_cpu_devices; i++)
        {
            cl_device_type device_type;
            err = clGetDeviceInfo(cpu_devices[i],
                                  CL_DEVICE_TYPE,
                                  sizeof(device_type),
                                  &device_type,
                                  nullptr);
            BOOST_CHECK_EQUAL(err, CL_SUCCESS);
            BOOST_CHECK((device_type & CL_DEVICE_TYPE_CPU) != 0);
        }
    }

    // 测试获取GPU设备
    cl_uint num_gpu_devices = 0;
    err                     = clGetDeviceIDs(
        platform, CL_DEVICE_TYPE_GPU, 0, nullptr, &num_gpu_devices);
    // 不要求必须有GPU设备，因为可能不存在

    if (num_gpu_devices > 0)
    {
        std::vector<cl_device_id> gpu_devices(num_gpu_devices);
        err = clGetDeviceIDs(platform,
                             CL_DEVICE_TYPE_GPU,
                             num_gpu_devices,
                             gpu_devices.data(),
                             nullptr);
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);

        for (cl_uint i = 0; i < num_gpu_devices; i++)
        {
            cl_device_type device_type;
            err = clGetDeviceInfo(gpu_devices[i],
                                  CL_DEVICE_TYPE,
                                  sizeof(device_type),
                                  &device_type,
                                  nullptr);
            BOOST_CHECK_EQUAL(err, CL_SUCCESS);
            BOOST_CHECK((device_type & CL_DEVICE_TYPE_GPU) != 0);
        }
    }
}

// 测试平台扩展功能
BOOST_AUTO_TEST_CASE(TestPlatformExtensions)
{
    cl_uint num_platforms = 0;
    cl_int  err           = clGetPlatformIDs(0, nullptr, &num_platforms);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    BOOST_REQUIRE_GT(num_platforms, 0);

    std::vector<cl_platform_id> platforms(num_platforms);
    err = clGetPlatformIDs(num_platforms, platforms.data(), nullptr);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    cl_platform_id platform = platforms[0];

    // 获取平台扩展列表
    size_t extensions_size = 0;
    err                    = clGetPlatformInfo(
        platform, CL_PLATFORM_EXTENSIONS, 0, nullptr, &extensions_size);
    BOOST_CHECK_EQUAL(err, CL_SUCCESS);

    if (extensions_size > 0)
    {
        std::vector<char> extensions(extensions_size);
        err = clGetPlatformInfo(platform,
                                CL_PLATFORM_EXTENSIONS,
                                extensions_size,
                                extensions.data(),
                                nullptr);
        std::cout << boost::format("Platform extensions: %s\n") %
                         extensions.data();
        BOOST_CHECK_EQUAL(err, CL_SUCCESS);
    }
}
